/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-09-15 19:45:07
 * @LastEditTime: 2021-10-09 09:57:30
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */
#include "ft_assert.h"
#include "parameters.h"
#include "f_sdio.h"
#include "f_sdio_hw.h"

extern u32 FSdioCtrlReset(FSdioCtrl *ctrl_p, u32 reset_bits);
extern u32 FSdioIntrInit(FSdioCtrl *ctrl_p);
extern u32 FSdioIDmaInit(FSdioCtrl *ctrl_p);
extern void FSdioDisableClk(FSdioCtrl *ctrl_p);
extern void FSdioEnableClk(FSdioCtrl *ctrl_p);
extern void FSdioCardPowerOff(FSdioCtrl *ctrl_p);

u32 FSdioInitialize(FSdioCtrl *ctrl_p, const FSdioConfig *config_p)
{
    FT_ASSERTZERONUM(ctrl_p && config_p);
    u32 ret = FSDIO_SUCCESS;
    u32 reg_val;
    int retries = 0;

    /* copy configs */
    if (config_p != &ctrl_p->config)
    {
        ctrl_p->config = *config_p;
    }

    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_UHS_REG_OFFSET, FSDIO_UHS_REG_VOLT_180); /* select 3.3v */
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_PWREN_OFFSET, FSDIO_PWREN_ENABLE); /* power on */
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_BUS_MODE_OFFSET, FSDIO_BUS_MODE_DE); /* enable idma */
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_CNTRL_OFFSET, FSDIO_CNTRL_USE_INTERNAL_DMAC | FSDIO_CNTRL_INT_ENABLE); /* enable idma and global intr */

    /* set fifo */
    reg_val = FSDIO_FIFOTH(FSDIO_FIFOTH_DMA_TRANS_128, 127, 128); /* 0x607f0080 */
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_FIFOTH_OFFSET, reg_val);

    /* set clk div and clk source */
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_UHS_REG_EXT_OFFSET, 0x0);
    reg_val = FSDIO_UHS_CLK_DIV(5) | FSDIO_UHS_EXT_CLK_ENA;
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_UHS_REG_EXT_OFFSET, reg_val);

    /* wait clk ready */
    retries = 0;
    do
    {
        reg_val = FSDIO_READ_REG(ctrl_p, FSDIO_REG_CCLK_READY_OFFSET);
    } while ((FSDIO_CIU_CLK_READY != reg_val & FSDIO_CIU_CLK_READY) && 
             (FSDIO_TIMEOUT > ++retries));
    
    if (FSDIO_TIMEOUT <= retries)
    {
        FSDIO_ERROR("wait clk ready timeout !!");
        return FSDIO_ERR_TIMEOUT;
    }

    /* update clk div to set 400kHz clk */
    FSDIO_CLR_BITS(ctrl_p, FSDIO_REG_CLKENA_OFFSET, FSDIO_CLKENA_CCLK_ENABLE); /* disable clk */
    reg_val = FSDIO_CLK_DIV(0x7e, 0x7d, 0xfa);
    FSDIO_WRITE_REG(ctrl_p, FSDIO_REG_CLKDIV_OFFSET, reg_val);
    FSDIO_SET_BITS(ctrl_p, FSDIO_REG_CLKENA_OFFSET, FSDIO_CLKENA_CCLK_ENABLE); /* enable clk */

    /* read controller version */
    ctrl_p->version = FSDIO_READ_REG(ctrl_p, FSDIO_REG_VID_OFFSET);
    FSDIO_INFO("ctrl version is 0x%lx", ctrl_p->version);

    /* reset controller */
    ret = FSdioCtrlReset(ctrl_p, FSDIO_CNTRL_CONTROLLER_RESET | FSDIO_CNTRL_FIFO_RESET | FSDIO_CNTRL_DMA_RESET);
    if (FSDIO_SUCCESS != ret)
        return ret;

    /* clear interrupt status and set interrupt mask to known state */
    ret = FSdioIntrInit(ctrl_p);
    if (FSDIO_SUCCESS != ret)
        return ret;

    /* enable DMA */
    ret = FSdioIDmaInit(ctrl_p);
    if (FSDIO_SUCCESS != ret)
        return ret;

    ctrl_p->is_ready = FT_COMPONENT_IS_READY; 
    return ret;   
}

void FSdioDeInitialize(FSdioCtrl *ctrl_p)
{
    FT_ASSERTNONERETURN(ctrl_p);
    FSdioDisableClk(ctrl_p);
    FSdioCardPowerOff(ctrl_p);
    FSDIO_CLR_BITS(ctrl_p, FSDIO_REG_UHS_REG_OFFSET, FSDIO_UHS_REG_VOLT_180);
    return;
}